# !/usr/bin/env python3

import sys
import argparse
from utils.utils import Utils
from common.logger import log
from suite.suite_repo import DEFAULT_SUITE
from workload.workloads_manager import WorkloadManager
from utils.utils import ErrorHandler
import workload.registered_workloads as registered_workloads
from common.benchmark_var import ConfigOptions as Options, StatusCode, GlobalVar


class CmdParser:
    """
    Command lines parser
    """
    _parser = argparse.ArgumentParser(add_help=False, conflict_handler='resolve',
                                      formatter_class=argparse.RawTextHelpFormatter)

    def __init__(self):
        self.options = None
        self.config_file = None
        self.INFO = {
            Options.ACTION: 'Set action for ServerBench.\n'
                            'available action:\n'
                            'standard: default, build and run benchmarks\n'
                            'build   : build benchmark\n'
                            'run     : just run benchmark, skip building benchmarks\n'
                            'clean   : remove the directory and temp file',
            Options.MODE: 'Set Running Mode.\n'
                          'Server: benchmark Server\n'
                          'Desktop: benchmark Desktop',
            Options.TEST_TARGET: 'Specify test unit, benchmarks or suites\n'
                                 'Available choice: coremark, gxx,.. / CPU, MEMORY,....',
            Options.COPIES: 'Set copies number',
            Options.ITERATIONS: 'Set iteration number',
            Options.CONFIG: 'Set configuration file',
            Options.REPORT: 'Set report format.\n'
                            'Any combination of report type: all, pdf, csv, txt.\n'
                            'all: default. Output 3 types of reports',
            Options.DEBUG: 'Set debug mode.\n'
                           'Available mode:\n'
                           '0: default. Close debug mode\n'
                           '1: Open debug mode',
            Options.SKIP_FAIL: 'Set exit mode when testcases failed.\n'
                               'Available mode: 0, 1\n'
                               '0: default. Exit when testcases failed\n'
                               '1: skip testcases without exit',
            Options.SKIP_VERIFY: 'Set mode whether to verify files.\n'
                                 'Available mode: 0, 1\n'
                                 '0: default. Verify that the file is modified\n'
                                 '1: skip verify',
            Options.OUTPUT_DIR: 'Set directory to store log files and reports',
            Options.HELP: 'Show help information',
            Options.VERSION: 'Show current version information',
            Options.LIST_WORKLOADS: 'show workloads information',
            Options.LIST_SUITES: 'show suites information'
        }

    def parse(self):
        """
        parse command lines
        """
        self._parser.add_argument('-a', '--action', dest='action', type=str,
                                  choices=['standard', 'build', 'run', 'clean'], help=self.INFO[Options.ACTION])
        self._parser.add_argument('-t', '--test_target', dest='test_target', nargs='+', type=str,
                                  help=self.INFO[Options.TEST_TARGET])
        self._parser.add_argument('--mode', dest='mode', type=str, choices=tuple(DEFAULT_SUITE.keys()),
                                  help=self.INFO[Options.MODE])
        self._parser.add_argument('-c', '--copies', dest='copies', type=int, help=self.INFO[Options.COPIES])
        self._parser.add_argument('-i', '--iteration', dest='iterations', type=int, help=self.INFO[Options.ITERATIONS])
        self._parser.add_argument('-f', '--config', dest='config', type=str, default='config_sample.ini',
                                  help=self.INFO[Options.CONFIG])
        self._parser.add_argument('-r', '--report', dest='report', nargs='+', type=str,
                                  choices=['all', 'pdf', 'txt', 'csv'], help=self.INFO[Options.REPORT])
        self._parser.add_argument('-s', '--skipfail', dest='skip_fail', type=int, choices=[0, 1],
                                  help=self.INFO[Options.SKIP_FAIL])
        self._parser.add_argument('--skipverify', dest='skip_verify', type=int, choices=[0, 1],
                                  help=self.INFO[Options.SKIP_VERIFY])
        self._parser.add_argument('-d', '--debug', dest='debug', type=int, choices=[0, 1],
                                  help=self.INFO[Options.DEBUG])
        self._parser.add_argument('--output_dir', dest='output_dir', type=str, help=self.INFO[Options.OUTPUT_DIR])
        self._parser.add_argument('-h', '--help', dest='help', action='store_true', help=self.INFO[Options.HELP])
        self._parser.add_argument('-v', '--version', dest='version', action='store_true',
                                  help=self.INFO[Options.VERSION])
        self._parser.add_argument('-W', '--list_workloads', dest='list_workloads', action='store_true',
                                  help=self.INFO[Options.LIST_WORKLOADS])
        self._parser.add_argument('-S', '--list_Suites', dest='list_suites', action='store_true',
                                  help=self.INFO[Options.LIST_SUITES])

        try:
            self.options = self._parser.parse_args()
        except BaseException:
            log.error('Parse cli commands error')
            ErrorHandler.check_error(StatusCode.OPTION_PARSE_FAIL)

        if self.options.help:
            self._parser.print_help()
            sys.exit(0)
        if self.options.version:
            log.info('GCBS (V): {}'.format(GlobalVar.VERSION))
            sys.exit(0)
        if self.options.list_workloads:
            log.info('list all workloads info')
            self.list_all_workloads()
            sys.exit(0)
        if self.options.list_suites:
            log.info('list all suites info')
            self.list_all_suites()
            sys.exit(0)

        self.config_file = self.options.config
        return self.options.__dict__

    def get_config_file(self):
        return self.config_file

    def list_all_workloads(self):
        Utils.log_partition("Workload information")
        for mode in DEFAULT_SUITE:
            workloads = []
            mode_suite = DEFAULT_SUITE.get(mode)
            self.get_workloads(mode_suite, workloads)
            print("")
            Utils.log_partition("{} mode".format(mode))
            print("{}DESC".format("WORKLOAD".ljust(30)))
            print("".ljust(70, "-"))
            for workload in sorted(workloads):
                WorkloadClass = WorkloadManager.get_workload_class(workload)
                print("{}{}".format(workload.ljust(30), WorkloadClass.DESC))

    def get_workloads(self, suite: dict, workloads: list):
        if suite.get('workloads'):
            workloads.extend(suite.get('workloads'))
        if suite.get('subsuites'):
            for suite in suite.get('subsuites'):
                self.get_workloads(suite, workloads)

    def list_all_suites(self):
        Utils.log_partition("Suite information")
        for mode in DEFAULT_SUITE:
            suites = []
            mode_suite = DEFAULT_SUITE.get(mode)
            self.get_suites(mode_suite, suites)
            Utils.log_partition("{} mode".format(mode))
            for suite in suites:
                print(suite)

    def get_suites(self, suite: dict, suites: list):
        suites.append(suite.get('name'))
        if suite.get('subsuites'):
            for sub_suite in suite.get('subsuites'):
                self.get_suites(sub_suite, suites)
